package cc.verywell.pureblock.func;

import java.nio.ByteBuffer;

import cc.verywell.pureblock.func.node.NodeBucket;
import cc.verywell.pureblock.log.Pblog;
import cc.verywell.pureblock.net.Msg;
import cc.verywell.pureblock.net.NormalSession;
import cc.verywell.pureblock.util.StringUtil;

/**
* 
* FuncProviderNode 的上级
* FuncProviderManager 的下级
* 由NormalSession负责保存;
* 
* Copyright 2019 TanYaqiu
* @author TanYaqiu 
* @address flat 601
* @date 2019年3月16日 下午6:32:48
*/
public class FuncProviderList implements FuncList {

	final private NodeBucket.ValueShell node;
	final FuncProvider[] list;
	final private byte[] cachelist;
	final private int cachewidth;
	final private FuncIndex cacheindex;
	public FuncProviderList(NodeBucket.ValueShell node, FuncProvider[] list, byte[] cachelist, int cachewidth, boolean isFullList) {
		this.node = node;
		this.list = list;
		this.cachelist = cachelist;
		this.cachewidth = cachewidth;
		this.cacheindex = FuncProviderManager.funcIndex.getFuncIndex(list,isFullList);
	}
	@Override
	public boolean hasFunc(FuncProvider provider) {
		return cacheindex.isFuncProviderExist(provider);
	}
	@Override
	public NodeBucket.ValueShell getNode() {
		return node;
	}

	/**
	 * 解包线程，这里出错会关掉channel;
	 * @param bb
	 * @return
	 */
	@Override
	public Msg decode(ByteBuffer bb, NormalSession nc) {
		//Pblog.print("____________", bb.remaining());
		int i = StringUtil.readLength(cachewidth, bb);
		FuncProvider o = list[i];//如果没有就直接报错了，然后就断开连接，这样很好;
		return o.decode(bb, nc);
	}

	/**
	 * {@link FuncIndex} cacheindex可以自编解决方案，比如连数据库;
	 * 
	 */
	@Override
	public void encode(Msg msg, NormalSession nc, ByteBuffer bb) {
		int i = cacheindex.getFuncProviderIndex(msg.getFunc());
		if(i<0)throw new IllegalArgumentException("MSG provider "+msg.getFunc()+" not in "+nc);
		i *= cachewidth;
		int j = i+cachewidth;
		while(i<j) {
			bb.put(cachelist[i++]);
		}
		msg.getFunc().encode(msg, nc, bb);
	}
	

//	@Override
//	public String funcName() {
//		return "__FuncProviderList__";
//	}
	@Override
	public String toString() {
		//用于出错时找原因;
		StringBuffer sb = new StringBuffer();
		sb.append(this.getClass().getSimpleName()).append("$").append(Integer.toHexString(this.hashCode()));
		sb.append('[');
		for (FuncProvider f : list) {
			sb.append(f.funcName()).append(',');
		}
		if(sb.codePointAt(sb.length()-1)==',')sb.setLength(sb.length()-1);
		sb.append(']');
		return sb.toString();
	}
	
	///////////////////////////////////////////////
	
	/**
	 * 返回true 会暂停读包, 
	 * 可以通过 NormalSession.startRead()恢复读包;
	 * 留意TimeOut,TimeoutRunner依然会自动断开连接的;
	 * @param Msg msg
	 * @param NormalSession nc
	 * @return true PauseRead;
	 */
	public boolean toDo(Msg msg,NormalSession nc) {
		 //TODO 未来建了包要另外线程，别再占用IO线程了。然后排队太多了要阻塞一下，也由这边控制;
		return msg.getFunc().toDo(msg, nc);
	}
	
	boolean running = false;
	public void newSession(NormalSession nc) {
		if(Pblog.DEBUG)Pblog.DEBUG("newSession ",this," in ",nc);
		if(running)throw new RuntimeException("session running");
		running = true;
		for (FuncProvider f : list) {
			try {
				f.newSession(nc);
			} catch (Throwable e) {
				if(Pblog.IO)Pblog.IO("new session ",f," faild in ",nc," ",e);
			}
		}
	}
	public void closeSession(NormalSession nc) {
		if(!running)throw new RuntimeException("session not running");
		running = false;
		for (FuncProvider f : list) {
			try {
				f.closeSession(nc);
			} catch (Throwable e) {
				if(Pblog.IO)Pblog.IO("close session ",f," faild in ",nc," ",e);
			}
		}
	}
	
	public void sessionTimeout(NormalSession nc) {
		if(!running)throw new RuntimeException("session not running");
		for (FuncProvider f : list) {
			try {
				f.sessionTimeout(nc);
			} catch (Throwable e) {
				if(Pblog.IO)Pblog.IO("timeout session ",f," faild in ",nc," ",e);
			}
		}
	}

	public void close(){
		//No thing need to do;
		throw new IllegalAccessError();
	}


}
